﻿#include <gui/GuiBase.h>
#include <res/static_resource.h>

constexpr ImWchar font_ranges[] =
{
	0x0020, 0x00FF, // Basic Latin + Latin Supplement
	0x2000, 0x206F, // General Punctuation
	0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
	0x31F0, 0x31FF, // Katakana Phonetic Extensions
	0xFF00, 0xFFEF, // Half-width characters
	0xFFFD, 0xFFFD, // Invalid
	0x4e00, 0x9FAF, // CJK Ideograms
	0,
};

#define ICON_MIN_CI 0xe900
#define ICON_MAX_CI 0xf421

constexpr ImWchar color_ranges[] =
{
	ICON_MIN_CI, ICON_MAX_CI,
	//0xe900,0xe911,
	0,
};

constexpr const char* menu_group_name_mapping[]
{
	u8"文件",
	u8"视图",
};

namespace primal
{
	namespace gui
	{
		struct
		{
			ImGuiContext* context;
			bool desktop_window_visbal;
			ImGuiWindowFlags dock_flags;
			utl::vector<Menu*> menus[MENU_GROUP_MAX];
			utl::vector<GuiWindowBase*> windows;
			utl::filebytes font_data;
			utl::filebytes font_color_data;
			ImFont* default_font;
			FontList other_font;
			bool is_init;
		}global{};

		void render()
		{
			impl_new_frame();
			const ImGuiViewport* viewport = ImGui::GetMainViewport();
			ImGui::SetNextWindowPos(viewport->WorkPos);
			ImGui::SetNextWindowSize(viewport->WorkSize);
			ImGui::SetNextWindowViewport(viewport->ID);

			ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
			ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
			ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{});
			ImGui::Begin("Desktop", &global.desktop_window_visbal, global.dock_flags);
			ImGui::PopStyleVar(3);

			if(ImGui::BeginMenuBar())
			{
				for(size_t i = 0; i < MENU_GROUP_MAX; i++)
				{
					auto& menu_item{ global.menus[i] };
					if(!menu_item.empty() && ImGui::BeginMenu(menu_group_name_mapping[i]))
					{
						for(auto item : menu_item)
						{
							item->render();
						}
						ImGui::EndMenu();
					}
				}
				ImGui::EndMenuBar();
			}
			ImGui::DockSpace(ImGui::GetID("m"));
			ImGui::End();

			for(auto& item : global.windows)
			{
				item->render(global.other_font);
			}

			ImGui::ShowDemoWindow();

			ImGui::Render();
			impl_draw();
		}

		bool initialize(GLFWwindow* window)
		{
			if(global.is_init)
			{
				return global.is_init;
			}

			{
				global.context = ImGui::CreateContext();
				ImGui::SetCurrentContext(global.context);
				global.dock_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBackground;
				global.desktop_window_visbal = true;
				global.other_font.resize(FontType_Count);
				ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable;

				primal::res::get_imgui_font(global.font_data);
				//primal::res::get_imgui_color_font(global.font_color_data);

				ImFontConfig cfg{};
				cfg.FontDataOwnedByAtlas = false;
				global.default_font = ImGui::GetIO().Fonts->AddFontFromMemoryTTF(global.font_data.data(), global.font_data.size(), 20.0f, &cfg, font_ranges);
				//global.other_font[FontType_Font_Max] = ImGui::GetIO().Fonts->AddFontFromMemoryTTF(global.font_data.data(), global.font_data.size(), 40.0f, &cfg, font_ranges);

				ImGui::GetIO().FontDefault = global.default_font;

				ImFontConfig color_cfg{};
				color_cfg.FontDataOwnedByAtlas = false;
				//global.other_font[FontType_Min] = ImGui::GetIO().Fonts->AddFontFromMemoryTTF(global.font_color_data.data(), global.font_color_data.size(), 20.0f, &color_cfg, color_ranges);
				//global.other_font[FontType_Max] = ImGui::GetIO().Fonts->AddFontFromMemoryTTF(global.font_color_data.data(), global.font_color_data.size(), 40.0f, &color_cfg, color_ranges);
				impl_initialize(window);
			}

			global.is_init = true;
			return global.is_init;
		}

		void gui_shutdown()
		{
			gui_impl_shutdown();
			ImGui::DestroyContext(global.context);
		}
	}
}

primal::GuiWindowBase::GuiWindowBase(const std::string& tit, bool default_show) : title{ tit }, is_show{ default_show }, menu{ tit }
{
	menu.binding_window(&this->is_show);
	primal::gui::global.windows.push_back(this);
}

primal::GuiWindowBase::~GuiWindowBase()
{
	utl::vector_delete_element(primal::gui::global.windows, this);
}

void primal::GuiWindowBase::render(const FontList& icon_ft)
{
	if (is_show)
	{
		ImGui::PushID(this);
		if (ImGui::Begin(this->title.c_str(), &is_show))
		{
			this->content(icon_ft);
		}
		ImGui::End();
		ImGui::PopID();
	}
}

primal::Menu::Menu(const std::string& t, MENU_GROUP mg) :title{ t }, group{ mg }
{
	primal::gui::global.menus[mg].push_back(this);
}

primal::Menu::~Menu()
{
	utl::vector_delete_element(primal::gui::global.menus[this->group], this);
}

//primal::MENU_GROUP primal::Menu::get_group() { return this->group; }

primal::WindowViewMenu::WindowViewMenu(const std::string& t) :Menu{ t,MENU_GROUP_VIEW }, window_life{}
{}

void primal::WindowViewMenu::render()
{
	assert(window_life != nullptr);
	ImGui::MenuItem(this->title.c_str(), nullptr, window_life);
}

void primal::WindowViewMenu::binding_window(bool* wl) { this->window_life = wl; }
